<template>
  <div class="tetris_page">
    <div class="game_view">
      <div class="left_view">
        <template v-for="(item, rowIndex) in renderBlocks" :key="rowIndex + 'row'">
          <div class="cell" v-for="(cell, cellIndex) in item" :key="cellIndex + 'cell' + cellIndex" :class="{['b' + cell]: true, blink: clearLineNumArr.includes(rowIndex)}"></div>
        </template>
        <div class="game_over" v-show="isGameOver">GAME OVER</div>
      </div>
      <div class="right_view">
        <div class="next_cells" v-if="nextTetris">
          <template v-for="(item, index) in nextTetris.blocks" :key="index + 'next-tetris-row'">
            <div class="cell" v-for="(cell, cellIndex) in item" :key="index + 'next-tetris-col' + cellIndex" :class="{['b' + cell]: true}"></div>
          </template>
        </div>
        <div class="info_con">
          <div class="info_item">
            <span>Score：</span>
            <span>{{ score }}</span>
          </div>
          <div class="info_item">
              <span>Level：</span>
              <span>{{ level }}</span>
          </div>
        </div>
        <div class="controls_con">
          <el-button type="primary" size="mini" v-if="isFirst" @click="startGame">开始游戏</el-button>
          <el-button type="primary" size="mini" v-if="isGameOver || isPause" @click="reStart">重新开始</el-button>
          <el-button type="primary" size="mini" v-if="!isFirst && !isGameOver" @click="pauseGame">{{ isPause ? '开始':'暂停' }}</el-button>
        </div>
      </div>
    </div>
  </div>
</template>
<script setup>
import { ref, computed, reactive } from 'vue';
import PlayFiled, { COLS } from './PlayField.js';
import Tetris, { TETRIS_TYPES, ROWS as TETRIS_ROWS } from './Tetris.js';
import { deepCopy, mergeBlocks } from './BlockUtils.js'


const isFirst = ref(true);
// 整体方法
const playField = reactive(new PlayFiled());
// 下一个方块
const nextTetris = ref(null);
// 当前方块
const currentTetris = ref(null);
// 消除的行数组
const clearLineNumArr = ref([]);

// 游戏是否结束
const isGameOver = ref(false);
// 游戏是否暂停
const isPause = ref(false);

// 得分
const score = ref(0);
// 等级
const level = computed(() => {
  return Math.floor(score.value / 2000) + 1;
});


// 定时向下一格
const timer = ref(null);
const run = () => {
  timer.value = setInterval(() => {
    moveTetris(1, 0);
  }, 500);
}

// 开始游戏
const startGame = () => {
  isFirst.value = false;
  setNewTetris(nextTetris.value); // 赋值新的方块
  run();
}

// 重新开始
const reStart = () => {
  isGameOver.value = false;
  isPause.value = false;
  playField.reset(); // 清除
  startGame(); // 重新开始  
}

// 暂停
const pauseGame = () => {
  clearInterval(timer.value);
  isPause.value = !isPause.value;
  if(!isPause.value) { // 重新开始
    run();
  }
}


// 计算属性保存渲染的数组
const renderBlocks = computed(() => {
  const copyBlocks = deepCopy(playField.blocks);
  if(!currentTetris.value) return copyBlocks;
  const { blocks: tBlocks, position } = currentTetris.value;
  const res = mergeBlocks(copyBlocks, tBlocks, position.row, position.col);
  return res;
})

// 是否超出边界
const isOutBound = (offsetRow, offsetCol, rotate) => {
  return playField.isOutBound(currentTetris.value, offsetRow, offsetCol, rotate);
}
// 旋转
const rotateTetris = (rotate) => {
  if (!isOutBound(0, 0, rotate)) {
    currentTetris.value.rotate(rotate); 
  } 
}
// 移动
const moveTetris = (offsetRow, offsetCol) => {
  if (!isOutBound(offsetRow, offsetCol, 0)) {
    currentTetris.value.move(offsetRow, offsetCol);
    return true;
  } else {
    if(offsetRow > 0) { // 如果向下移动到边界, 触发固化
      fixTetris();
    } 
    return false;
  }
}

// 赋值新的方块
const setNewTetris = (tetris) => {
  currentTetris.value = tetris;
  currentTetris.value.position = { row: -TETRIS_ROWS, col: (COLS - TETRIS_ROWS) / 2 }; // 定位到负方块行的位置

  for(let i = 0; i < TETRIS_ROWS; i++) { // 然后触发移动看看是否超出边界
    if(!moveTetris(1, 0)) break;
  }

  generateNewTetris(); // 生成新的下一个方块
}

// 生成新的方块
const generateNewTetris = () => {
  const randomInt = Math.floor(Math.random() * TETRIS_TYPES.length); // 随机生成一个方块
  const rotate = Math.floor(Math.random() * 3); // 随机旋转
  nextTetris.value = new Tetris(randomInt, rotate); // 生成新的下一个方块  
}

// 固化
const fixTetris = () => {
  addScore(50); // 固化一个方块，获得50分
  playField.merge(currentTetris.value);
  if(currentTetris.value.position.row < 0) { // 游戏结束
    isGameOver.value = true;
    clearInterval(timer.value);
    return;
  }
  clearLine(); // 执行消除
  setNewTetris(nextTetris.value); // 赋值新的方块
}

// 积分
const addScore = (num) => {
  score.value += num;
}

// 消除
const clearLine = () => {
  const { row: from } = currentTetris.value.position;
  const clearLineNum = playField.getCanRemoveRows(from, from + TETRIS_ROWS);
  clearLineNumArr.value = clearLineNum;
  // 积分，没消除n行，获得2^n * 100分
  addScore((2 ** clearLineNum.length) * 100);

  if(clearLineNum.length > 0) { // 消除
    setTimeout(() => {
      playField.removeRows(clearLineNum);
      clearLineNum.splice(0)
      clearLineNumArr.value = [];
    }, 200)
  }
}

// 键盘方向键按下
const onKeyDown = (e) => {
  switch (e.key) {
    case 'ArrowUp':
      rotateTetris(-1);
      break;
    case 'ArrowDown':
      moveTetris(1, 0);
      break;
    case 'ArrowLeft':
      moveTetris(0, -1);
      break;
    case 'ArrowRight':
      moveTetris(0, 1);
      break;
  }
}



onMounted(() => {
  generateNewTetris(); // 生成新的下一个方块
  // playField.blocks[19] = [1, 1, 1, 1, 1, 1, 1, 1, 0, 1]; // 底部
  // playField.blocks[18] = [1, 1, 1, 1, 1, 1, 1, 1, 0, 1]; // 底部
  // playField.blocks[17] = [1, 1, 1, 1, 1, 1, 1, 1, 0, 1]; // 底部
  // playField.blocks[16] = [1, 1, 1, 1, 1, 1, 1, 1, 0, 1]; // 底部
  // playField.blocks[15] = [1, 1, 1, 1, 1, 1, 1, 1, 0, 1]; // 底部
  // playField.blocks[14] = [1, 1, 1, 1, 1, 1, 1, 1, 0, 1]; // 底部
  document.addEventListener('keydown', (e) => {
    if(isGameOver.value || isPause.value) return;
    onKeyDown(e);
  })
})



</script>
<style scoped lang="scss">
$cell-size: 36px;
$cell-border-width: 3px;

$b1: #45b2b3;
$b2: #c6ef79;
$b3: #7d80f4;
$b4: #55aae7;
$b5: #dcdc0a;
$b6: #d7a109;
$b7: #e1423b;
.tetris_page {
  width: 100%;
  height: 100%;
  overflow: hidden;
  font-family: Impact, sans-serif;
  .game_view {
    padding: 20px 0;
    display: flex;
    justify-content: center;
    align-items: center;
    background-color: #1e1e1e;
    .left_view {
      width: calc($cell-size * 10);
      height: calc($cell-size * 20);
      display: flex;
      flex-wrap: wrap;
      border: 2px solid #666;
      position: relative;
      .game_over {
        position: absolute;
        top: 0;
        left: 0;
        right: 0;
        bottom: 0;
        background-color: rgba(0, 0, 0, 0.8);
        color: red;
        text-align: center;
        font-size: 36px;
        padding-top: calc($cell-size * 8);
        text-shadow: 0 0 16px yellow;
      }
    }
    .right_view {
      height: calc($cell-size * 20);
      display: flex;
      flex-direction: column;
      justify-content: space-between;
      width: calc($cell-size * 5);
      padding: 0 10px;
      .next_cells {
        display: flex;
        flex-wrap: wrap;
        align-content: start;
        width: calc($cell-size * 4);
        height: calc($cell-size * 4);
        padding: calc($cell-size / 2);
        margin-bottom: 3em;
      }
      .info_con {
        flex: 1;
        margin-bottom: 3em;
        .info_item {
          color: #fed26c;
          font-size: 18px;
          margin-bottom: 12px;
        }
      }
      .controls_con {
        padding: 24px 0;
        display: flex;
        justify-content: center;
        border-top: 2px solid #666;
      }
    }
    .cell {
      width: $cell-size;
      height: $cell-size;
      border: $cell-border-width solid #333;
      border-style: outset;
      box-sizing: border-box;
      background-color: transparent;
    }
    .cell.b0 {
      // visibility: hidden;
      border: 1px solid #000;
    }
    .cell.b1 {
      background-color: $b1;
      border-color: $b1;
    }
    .cell.b2 {
      background-color: $b2;
      border-color: $b2;
    }
    .cell.b3 {
      background-color: $b3;
      border-color: $b3;
    }
    .cell.b4 {
      background-color: $b4;
      border-color: $b4;
    }
    .cell.b5 {
      background-color: $b5;
      border-color: $b5;
    }
    .cell.b6 {
      background-color: $b6;
      border-color: $b6;
    }
    .cell.b7 {
      background-color: $b7;
      border-color: $b7;
    }

    .cell.blink {
      animation: blink 0.1s infinite;
    }

    @keyframes blink {
      0% {
        opacity: 1;
      }
      100% {
        opacity: 0.5;
      }
    }
  }
}
</style>